package run.halo.app.service;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.transaction.annotation.Transactional;
import run.halo.app.model.dto.CategoryWithSiteCountDTO;
import run.halo.app.model.entity.Category;
import run.halo.app.model.entity.Site;
import run.halo.app.model.entity.SiteCategory;
import run.halo.app.model.enums.SiteStatus;
import run.halo.app.service.base.CrudService;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Site category service interface.
 *
 * @author meazty
 * @since 2022/7/30 14:42
 **/
public interface SiteCategoryService extends CrudService<SiteCategory, Integer> {

    /**
     * Lists category by site id.
     *
     * @param siteId site id must not be null
     * @return a list of category
     */
    @NonNull
    List<Category> listCategoriesBy(@NonNull Integer siteId);

    /**
     * List category list map by site id collection.
     *
     * @param siteIds site id collection
     * @return a category list map (key: siteId, value: a list of category)
     */
    @NonNull
    Map<Integer, List<Category>> listCategoryListMap(@Nullable Collection<Integer> siteIds);

    /**
     * Lists site by category id.
     *
     * @param categoryId category id must not be null
     * @return a list of site
     */
    @NonNull
    List<Site> listSiteBy(@NonNull Integer categoryId);

    /**
     * Lists site by category id and site status.
     *
     * @param categoryId category id must not be null
     * @param status site status
     * @return a list of site
     */
    @NonNull
    List<Site> listSiteBy(@NonNull Integer categoryId, @NonNull SiteStatus status);

    /**
     * Lists site by category id and site status.
     *
     * @param categoryId category id must not be null
     * @param status     site status
     * @return a list of site
     */
    @NonNull
    List<Site> listSiteBy(@NonNull Integer categoryId, @NonNull Set<SiteStatus> status);

    /**
     * Lists site by category slug and site status.
     *
     * @param slug category slug must not be null
     * @param status site status
     * @return a list of site
     */
    @NonNull
    List<Site> listSiteBy(@NonNull String slug, @NonNull SiteStatus status);

    /**
     * Lists site by category slug and site status.
     *
     * @param slug   category slug must not be null
     * @param status site status
     * @return a list of site
     */
    @NonNull
    List<Site> listSiteBy(@NonNull String slug, @NonNull Set<SiteStatus> status);

    /**
     * Pages site by category id.
     *
     * @param categoryId category id must not be null
     * @param pageable pageable
     * @return page of site
     */
    @NonNull
    Page<Site> pageSiteBy(@NonNull Integer categoryId, Pageable pageable);

    /**
     * Pages site by category id and site status.
     *
     * @param categoryId category id must not be null
     * @param status site status
     * @param pageable pageable
     * @return page of site
     */
    @NonNull
    Page<Site> pageSiteBy(@NonNull Integer categoryId, @NonNull SiteStatus status,
        Pageable pageable);

    /**
     * Pages site by category id and site status.
     *
     * @param categoryId category id must not be null
     * @param status     site status
     * @param pageable   pageable
     * @return page of site
     */
    @NonNull
    Page<Site> pageSiteBy(
        @NonNull Integer categoryId, @NonNull Set<SiteStatus> status, Pageable pageable);

    /**
     * Merges or creates site categories by site id and category id set if absent.
     *
     * @param siteId site id must not be null
     * @param categoryIds category id set
     * @return a list of site category
     */
    @NonNull
    List<SiteCategory> mergeOrCreateByIfAbsent(@NonNull Integer siteId,
        @Nullable Set<Integer> categoryIds);

    /**
     * Lists by site id.
     *
     * @param siteId site id must not be null
     * @return a list of site category
     */
    @NonNull
    List<SiteCategory> listBySiteId(@NonNull Integer siteId);

    /**
     * Lists by category id.
     *
     * @param categoryId category id must not be null
     * @return a list of site category
     */
    @NonNull
    List<SiteCategory> listByCategoryId(@NonNull Integer categoryId);

    /**
     * List category id set by site id.
     *
     * @param siteId site id must not be null
     * @return a set of category id
     */
    @NonNull
    Set<Integer> listCategoryIdsBySiteId(@NonNull Integer siteId);

    /**
     * Removes site categories by site id.
     *
     * @param siteId site id must not be null
     * @return a list of site category deleted
     */
    @NonNull
    @Transactional(rollbackFor = Exception.class)
    List<SiteCategory> removeBySiteId(@NonNull Integer siteId);

    /**
     * Removes site categories by category id.
     *
     * @param categoryId category id must not be null
     * @return a list of site category deleted
     */
    @NonNull
    @Transactional(rollbackFor = Exception.class)
    List<SiteCategory> removeByCategoryId(@NonNull Integer categoryId);

    /**
     * Lists category with site count.
     *
     * @param sort sort info
     * @return a list of category dto
     */
    @NonNull
    List<CategoryWithSiteCountDTO> listCategoryWithSiteCountDto(@NonNull Sort sort);

    /**
     * Lists by category id.
     *
     * @param categoryIdList category id must not be empty
     * @return a list of site category
     */
    @NonNull
    List<SiteCategory> listByCategoryIdList(@NonNull List<Integer> categoryIdList);
}
